package com.hitgo.soccer.core;

import java.nio.ByteBuffer;
import java.util.ArrayList;

import com.hitgo.soccer.config.MatchConfig;
import com.hitgo.soccer.utils.CalcUtil;


public class Match
{
	public static final int MATCH_TYPE_FRIENDSHIP 	= 0;
	public static final int MATCH_TYPE_LEAGUE		= 1;
	public static final int MATCH_TYPE_ARENA		= 2;
	
	private MatchState matchState;
	
	private ByteBuffer matchData;
	private Team team1;
	private Team team2;
	
	private Team attackTeam;
	private Team defindTeam;
	
	private Football ball;
	private boolean isSecondHalf = false;

	private boolean isObstructing;
	
	public Match(Team team1, Team team2)
	{
		this.attackTeam = this.team1 = team1;
		this.defindTeam = this.team2 = team2;
		
		matchState = MatchState.BEFORE;
		
		ball = new Football();
	}
	
	public byte[] startMatch()
	{
		if(team1 == null || team2 == null)
			return null;

		if(matchData == null)
			matchData = ByteBuffer.allocate(10*1024);
		else
			matchData.reset();
		
		// 
		for(int nRound = 0; nRound < MatchConfig.maxRound; nRound++)
		{
			this.isObstructing = false;
			switch(this.matchState)
			{
			case HALF_TIME:	
				isSecondHalf = true;
			case BEFORE:
			case GOAL:
			case GOAL_LEAN:
			case CATCHED:	// 守门员得球
			case FOUL:		// 犯规
			case CORNER_KICK:
			case THROW_IN:
				ready();
				break;
			case KICK_OFF:	
			case HIT:
				kickOff();
				break;
			default:
				playerAction();
				break;
			}
			// 比赛状态, 球x y, 当前球队 1/2, 持球球员Id x y
			byte bCurTeam = 1;
			if(this.attackTeam != this.team1)
				bCurTeam = 2;
			Player curPlayer = null;
			if(this.matchState != MatchState.FOUL)
			{
				curPlayer = attackTeam.getCurPlayer();
			}
			else
			{
				curPlayer = this.defindTeam.getCurPlayer();
			}

			System.out.println(nRound + ".\t" + bCurTeam + " - "+ this.matchState + "\tball(" + ball.getX() + "," + ball.getY() + ")");
						// 序列化
			matchData.putShort((short)this.matchState.getValue());	// 2 byte		当前动作
			this.matchData.putShort(ball.getX());					// 2 bytes		球的 x位置		
			this.matchData.putShort(ball.getY());					// 2 bytes		球的 y位置
			short sPosition = (short) (bCurTeam<<8);
			sPosition += curPlayer.getPosition();
			this.matchData.putShort(sPosition);						// 2 bytes		当前球员的ID
			this.matchData.putShort(curPlayer.getX());				// 2 bytes		球员的X
			this.matchData.putShort(curPlayer.getY());				// 2 bytes		球员的Y
			
			if(nRound == MatchConfig.maxRound/2)
			{
				this.matchState = MatchState.HALF_TIME;
			}
			
		}
		matchData.flip();
		byte[] bRet = new byte[matchData.limit()];
		matchData.get(bRet);
		return bRet;
		
	}
	// 攻守异位
	private void exchangeAD()
	{
		Team tmp = this.attackTeam; 
		this.attackTeam = defindTeam;
		this.defindTeam = tmp;
	}
	
	private boolean directionL2R()
	{
		if(this.isSecondHalf == false)
		{
			if(this.attackTeam == this.team1)
				return true;
			return false;
		}
		else
		{
			if(this.attackTeam == this.team2)
				return true;
			return false;
		}
	}
	
	private void ready()
	{
		switch(this.matchState)
		{
		case BEFORE:
			this.team1.setPlayersPosition(true);
			this.team2.setPlayersPosition(false);
			
			this.attackTeam = this.team1;
			this.defindTeam = this.team2;
			
			this.ball.reset();
			break;
		case HALF_TIME:
			// 交换场地
			this.team2.setPlayersPosition(true);
			this.team1.setPlayersPosition(false);
			
			this.attackTeam = this.team2;
			this.defindTeam = this.team1;
			this.ball.reset();
			break;
		case GOAL:
		case CATCHED:
			// 进球后，攻守互换
			
			this.exchangeAD();
			if(isSecondHalf == false)
			{
				this.team1.setPlayersPosition(true);
				this.team2.setPlayersPosition(false);
			}
			else
			{
				this.team2.setPlayersPosition(true);
				this.team1.setPlayersPosition(false);
			}
			this.ball.reset();
			
			break;
		case GOAL_LEAN:		
			this.exchangeAD();
			Player keeper = this.attackTeam.getGoalkeeper();
			this.attackTeam.setCurPlayer(keeper);
			this.ball.setX(keeper.getX());
			this.ball.setY(keeper.getY());
			break;
		case THROW_IN:
			
			break;
		case CORNER_KICK:
			break;
		}

		short ballX = this.ball.getX();
		short ballY = this.ball.getY();

		Player src = this.attackTeam.getNearestPlayer(ballX, ballY);
		src.setX(ballX);
		src.setY(ballY);
		this.attackTeam.setCurPlayer(src);
		this.matchState = MatchState.KICK_OFF;
	}

	// 传球目标者
	private Player getDestPlayer()
	{
		boolean isLongPass = false;
		Player ballHolder = this.attackTeam.getCurPlayer();
		// 判断是否长传
		if(CalcUtil.nextInt(100) <= ballHolder.getVision()/200)
		{
			isLongPass = true ;
			
			this.matchState = MatchState.LONG_PASS;
		}
		// 判断进攻方向
		boolean isL2R = directionL2R();
		
		ArrayList<Player> alP = attackTeam.getFrontPlayers(isL2R);
		
		int nFrontNum = alP.size();
		if(nFrontNum == 0)
			return null;

		int nPIndex = 0;
		if(nFrontNum == 1)
			return alP.get(0);
		if(isLongPass)
		{
			nPIndex = CalcUtil.nextInt(nFrontNum - nFrontNum/2) + 1;
		}
		else
		{
			nPIndex = CalcUtil.nextInt(nFrontNum/2);
		}
		
		return alP.get(nPIndex);
	}
	
	private void kickOff()
	{
		this.matchState = MatchState.NORMAL_PASS;
		Player sP = this.attackTeam.getCurPlayer();
		Player dP = getDestPlayer();
	

		int dX = dP.getX();
		int dY = dP.getY();
		
		int rV= CalcUtil.nextInt(4);
		int passValue = sP.getPass();
		switch(rV)
		{
		//实际传球点为（a+（200-传球）/10,b）
		case 0:
			dX = dX + (200 - passValue)/10;
			break;
		// 	则或（a,b+（200-传球）*/10）
		case 1:
			dY = dY + (200 - passValue)/10;
			break;
		//	或（a-（200-传球）*/10,b）
		case 2:
			dX = dX - (200 - passValue)/10;
			break;
		// 或（a,b-（200-传球）*/10）	
		default:
			dY = dY - (200 - passValue)/10;
			break;
		}
		if(dX < 0)
			dX = 0;
		if(dX > MatchConfig.fieldWidth)
			dX = MatchConfig.fieldWidth;
		
		if(dY < 0)
			dY = 0;
		
		if(dY > MatchConfig.fieldHeight)
			dY = MatchConfig.fieldHeight;
		this.ball.setX((short) dX);
		this.ball.setY((short) dY);
		

		Player aSP = this.attackTeam.getNearestPlayer(dX, dY);
		Player dSP = this.defindTeam.getNearestPlayer(dX, dY);
		
		double sd = CalcUtil.getDistance(dX, dY, aSP.getX(), aSP.getY());
		double dd = CalcUtil.getDistance(dX, dY, dSP.getX(), dSP.getY());
		
		if(sd / aSP.getSpeed() < dd / dSP.getSpeed())
		{
			this.exchangeAD();
			this.attackTeam.setCurPlayer(dSP);
			dSP.setX((short)dX);
			dSP.setY((short)dY);
		}
		else
		{
			this.attackTeam.setCurPlayer(aSP);
			aSP.setX((short)dX);
			aSP.setY((short)dY);
		}
		
	}
	
	private void playerAction()
	{
		//1 防守
		if(this.defind())
			return ;
		
		//2. 射门
		if(canShot() == true)
		{	
			shot();
			return ;
		}
		
		// 3. 传球
		if(passBall() == true)
			return ;
		
		// 4. 带球
		dribbling();
	}
	
	//	防守
	/*
	 * 
	 *  当防守不成功时，返回false;
	 *  防守成功或者犯规，都返回true
	 * 
	 */
	
	private boolean defind()
	{
		Player attackPlayer = attackTeam.getCurPlayer();
		short x = attackPlayer.getX();
		short y = attackPlayer.getY();		
		Player definedPlayer = this.defindTeam.getDefindPlayer(x, y);
		if(definedPlayer != null)
		{
			defindTeam.setCurPlayer(definedPlayer);
			
			// 1 .减少进攻人的属性
			this.isObstructing = true;
			
			//2. 判断抢断
			if(CalcUtil.nextInt(100) <= definedPlayer.getFierce()/20)
			{
				if(definedPlayer.getSteal() > attackPlayer.getStrength())
				{
					//1.1 是否犯规
					if(isFoul(definedPlayer))
					{
						this.matchState = MatchState.FOUL;
					}
					else
					{
						this.matchState = MatchState.STEAL;
						attackPlayer.pause();
						this.exchangeAD();
					}
					return true;
				}
			}
			definedPlayer.pause();
		}
		
		return false;
		
	}
	
	// 计算是否犯规
	private boolean isFoul(Player definder)
	{
		//TODO 需要计算概率
		return false;
	}
	
	/*
	 * 	射门
	 *  首先判断能否射门，如果不能，return false
	 * 	如果可以射门，射门的角度，和
	 */
	private boolean shot()
	{
		Player attackPalyer = this.attackTeam.getCurPlayer();
		//角度系数 =(rand（）*4-1)+射门/200
		int nShot = attackPalyer.getShot();
		if(this.isObstructing)
			nShot -= 3;	// TODO: 影响的数值
		double shotPoint = (Math.random()*4-1 + nShot/200);
		
		Player keeper = this.defindTeam.getGoalkeeper();
		
		if(shotPoint < 0)
		{
			this.matchState = MatchState.GOAL_LEAN;
			return true;
		}

		

		//	射正后，判断是否进球：决定是否进球，IF 角度系数*(1-位置感/200）*力量>反应，then进球
		if((shotPoint * (1-keeper.getPointSense()/200) * attackPalyer.getStrength()) >  keeper.getReaction())
		{
			this.matchState = MatchState.GOAL;			
		}
		else	//	不进球判断是否手接住：IF 手控球>力量*1.5，then手控 
		{
			if(keeper.getCatched() > attackPalyer.getStrength() * 1.5)
				this.matchState = MatchState.CATCHED;
			else
			{
				this.matchState = MatchState.HIT;
				this.exchangeAD();
				this.attackTeam.setCurPlayer(keeper);
			}
		}
		return true;
	}
	
	private double goalDistance(Player aP)
	{
		int goalX = MatchConfig.fieldWidth;
		
		if(this.directionL2R()== false)
		{
			goalX = 0;
		}		
		int nPX = aP.getX();
		int nPY = aP.getY();
		
		if(nPY >= MatchConfig.goalTopY && nPY <= MatchConfig.goalDownY)
			return Math.abs(nPX - goalX);
		
		int nGoalY = MatchConfig.goalDownY;
		if(nPY < MatchConfig.fieldWidth /2)
		{
			nGoalY = MatchConfig.goalTopY;
		}
	
		double nDY = 0;
		double nDX = 0;
		nDY = Math.abs(nPY - nGoalY);
		nDY *= nDY;
		
		nDX = Math.abs(nPX - goalX);
		nDX *= nDX;
		return Math.sqrt(nDX + nDY);
	}
	
	private double goalXDistance(Player aP)
	{
		int goalX = MatchConfig.fieldWidth;
		
		if(this.directionL2R()== false)
		{
			goalX = 0;
		}		
		int nPX = aP.getX();
		
	
		double nDX = 0;
		
		nDX = Math.abs(nPX - goalX);
		return nDX;
	}
	
	private double goalYDistance(Player aP)
	{
		int nPY = aP.getY();
		
		if(nPY >= MatchConfig.goalTopY && nPY <= MatchConfig.goalDownY)
			return 0;
		
		int nGoalY = MatchConfig.goalDownY;
		if(nPY < MatchConfig.fieldWidth /2)
		{
			nGoalY = MatchConfig.goalTopY;
		}
	
		double nDY = 0;
		nDY = Math.abs(nPY - nGoalY);
		return nDY;
	}
	
	private boolean canShot()
	{
		// 1，在射门范围内射门的概率=射门/200，
		// 2，决定射门角度系数=(rand（）*4-1)+射门/200
		Player attackPalyer = this.attackTeam.getCurPlayer();
		
		double goalD = this.goalDistance(attackPalyer);
		// 根据自身数值 判断是否可以射门
		
		if(attackPalyer.getStrength() / 2 < goalD)
			return false;
		
		return true;
	}
	
	
	// 传球
	private boolean passBall()
	{
		//意识，决定传球概率=意识*在自己前方的球员数/500
		int nFCount = this.attackTeam.getFrontPlayerNum(directionL2R());
		if(nFCount == 0)
			return false;
		Player cp = this.attackTeam.getCurPlayer();
		int nCoun = cp.getConscious();
		if(this.isObstructing)
			nCoun -= 3; //TODO 修正该值
		int passRand = nCoun * nFCount / 500;
		
		if(ball.getX() > 0 && ball.getX() < MatchConfig.fieldWidth
				&& ball.getY() > 0 && ball.getY() < MatchConfig.fieldHeight
				&& CalcUtil.nextInt(100) >= passRand)
			return false;
		
		this.kickOff();
		return true;
	}
	
	//带球
	private boolean dribbling()
	{
		this.matchState = MatchState.DRIBBLING;
		Player aP = this.attackTeam.getCurPlayer();
		short nSpeed = aP.getMoveSpeed();
		if(this.isObstructing)
			nSpeed -= 3;	// TODO: 影响的数值
		
		boolean isL2R = this.directionL2R();
		if(isL2R == false)
			nSpeed = (short) -nSpeed;
		
		int nGoalD = (int) this.goalDistance(aP);
		int nXD = (int) this.goalXDistance(aP);
		int nYD = (int) this.goalYDistance(aP);
		
		//计算 目标点 
		int nXSpeed = nSpeed * nXD / nGoalD;
		int nYSpeed = Math.abs(nSpeed * nYD / nGoalD);
		short y = (short) (aP.getY() + nYSpeed);
		if(aP.getY() > MatchConfig.goalDownY)
		{
			y = (short) (aP.getY() - nYSpeed);
		}
		short x = (short) (aP.getX() + nXSpeed);
		
		// 判断是否出界
		if(x < 0 ||  x > MatchConfig.fieldWidth)
		{
			this.matchState = MatchState.THROW_IN;
			return false;
		}
		
		if(y < 0)
		{
			if(isL2R)
				this.matchState = MatchState.CORNER_KICK;
			else
				this.matchState = MatchState.CATCHED;
			return false;
		}
		if(y > MatchConfig.fieldHeight)
		{
			if(isL2R)
				this.matchState = MatchState.CATCHED;
			else
				this.matchState = MatchState.CORNER_KICK;
			return false;
		}
		
		aP.setX(x);
		aP.setY(y);
		
		this.ball.setX(x);
		this.ball.setY(y);
		
		playersMove();
		
		return true;
	}
	
	private void playersMove()
	{
		// 所有运动员的运动方向和路线
		boolean isL2R = this.directionL2R();
		
		this.team1.allPlayersMove(isL2R);
		this.team2.allPlayersMove(isL2R);
	}
}
